/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package metodos;

import Compilador.Plantilla;
import datos.Datos;
import datos.Regla;
import java.lang.String;
import java.util.ArrayList;


public class IndiceGini extends Metodo {

    Datos datos; //contiene todos los datos con los que se van a trabajar
    String[] titulos; //contiene los titulos localmente
    ArrayList<Regla> reglas; //aqui se almacenan las reglas de todos los datos
    ArrayList<String> usados;//aqui se almacenan los nodos usados.
    private ArrayList<Regla> reglasAuxiliares;
    private boolean nuevaRegla;
    private int profundidad;

    public IndiceGini(Datos datos) {
        this.datos = datos;
        titulos = datos.getTitulos();
        reglas = new ArrayList<Regla>();
        usados = new ArrayList<String>();
        nuevaRegla = true;
        profundidad = 0;
        reglasAuxiliares = new ArrayList<Regla>();
    }

    @Override
    public void Calcular() {

        recurso(datos);
    }

    private void recurso(Datos datos) {
        profundidad++;

        //Si no hay datos termina.
        if (datos.getLista().isEmpty()) {
            return;
        }

        if (profundidad >= titulos.length + 1) {
            return;
        }

        ArrayList<ArrayList<String>> listaDatos = datos.getLista();

        ArrayList<Double> giniColumnas = new ArrayList<Double>();
        ArrayList<String> nombresColumnas = new ArrayList<String>();
        ArrayList<ArrayList<TablaGini>> tablasGini = new ArrayList<ArrayList<TablaGini>>();

        for (int i = 0; i < titulos.length; i++) {
            if (titulos[i].equals(datos.getNombreClase())) {
                continue;
            }
            if (estaUsado(titulos[i])) {
                continue;
            }

            ArrayList<String> valoresColumna = obtenerValoresColumna(datos, i);
            ArrayList<TablaGini> tablasGiniColumna = new ArrayList<TablaGini>();

            for (int j = 0; j < valoresColumna.size(); j++) {
                TablaGini tablaGini = new TablaGini(listaDatos, valoresColumna.get(j));
                tablaGini.Determinar(i, getIndiceTitulo(titulos, datos.getNombreClase()));
                tablasGiniColumna.add(tablaGini);
            }

            giniColumnas.add(giniColumna(tablasGiniColumna, listaDatos.size()));
            nombresColumnas.add(titulos[i]);
            tablasGini.add(tablasGiniColumna);
        }

        double indiceGiniMenor = 1;
        int indiceColumnaMenor = 0;
        for (int i = 0; i < giniColumnas.size(); i++) {
            if (indiceGiniMenor >= giniColumnas.get(i)) {
                indiceGiniMenor = giniColumnas.get(i);
                indiceColumnaMenor = i;
            }
        }
        //se agrega el elemento que ya esta usado
        usados.add(nombresColumnas.get(indiceColumnaMenor));
        //System.out.println("Usados" + usados);

        //System.out.println("el indice gini menor es de " + indiceGiniMenor + " y pertenece a la columna " + nombresColumnas.get(indiceColumnaMenor));

        ArrayList<TablaGini> tablasRecursividad = tablasGini.get(indiceColumnaMenor);
        //System.out.println("tamaño de las tablas de recursividad " + tablasRecursividad.size() + " en profundidad " + profundidad);
        for (int i = 0; i < tablasRecursividad.size(); i++) {
            Regla r = new Regla();
            ///System.out.println("Profundidad: " + profundidad);
            System.out.println(tablasRecursividad.get(i).valorColumna +" cantidad de ciclos "+tablasRecursividad.size());
            if (tablasRecursividad.get(i).gini == 0) {
                //System.out.println("Entra a gini 0");
                if (nuevaRegla) {
                    r.setNombreClase(datos.getNombreClase());
                    r.setValorClase(tablasRecursividad.get(i).mayorValorClase);
                    r.AgregarRegla(nombresColumnas.get(indiceColumnaMenor), tablasRecursividad.get(i).valorColumna);
                    reglas.add(r);
                } else {
                    for (int j = 0; j < reglasAuxiliares.size(); j++) {
                        r.AgregarRegla(reglasAuxiliares.get(j).getNombreAtributo(), reglasAuxiliares.get(j).getValor());
                        //reglasAuxiliares.remove(j);
                        //break;
                    }

                    r.setNombreClase(datos.getNombreClase());
                    r.setValorClase(tablasRecursividad.get(i).mayorValorClase);
                    r.AgregarRegla(nombresColumnas.get(indiceColumnaMenor), tablasRecursividad.get(i).valorColumna);
                    reglas.add(r);
                }
            } else {
                //System.out.println("Entra a nueva regla");
                nuevaRegla = false;
                Datos nDatos = new Datos();
                nDatos.setNombreClase(datos.getNombreClase());
                nDatos.setTitulos(titulos);
                ArrayList<ArrayList<String>> nuevaLista = limpiarTabla(datos.getLista(), indiceColumnaMenor, tablasRecursividad.get(i).valorColumna);
                nDatos.setLista(nuevaLista);

                Regla re = new Regla();
                re.AgregarRegla(nombresColumnas.get(indiceColumnaMenor), tablasRecursividad.get(i).valorColumna);
                reglasAuxiliares.add(re);
                recurso(nDatos);
                reglasAuxiliares.remove(reglasAuxiliares.size()-1);
                profundidad--;
                System.out.println("Usados" + usados);
                usados.remove(usados.size() - 1);


            }
        }


    }

    //TODO  hacer algoritmo para obtener valores unicos de las columnas
    private ArrayList<String> obtenerValoresColumna(Datos datos, int indiceColumna) {
        ArrayList<String> salida = new ArrayList<String>();
        for (int i = 0; i < datos.getLista().size(); i++) {
            ArrayList<String> val = datos.getLista().get(i);
            AgregarValor(val.get(indiceColumna), salida);
        }
        System.out.println(salida);
        return salida;
    }

    //<editor-fold defaultstate="collapsed" desc="+Funciones Auxiliares">
    /**
     * Agrega elemento a la lista
     * @param valor
     * @param array
     * @return
     */
    public int AgregarValor(String valor, ArrayList<String> array) {
        int indice = BuscarValor(valor, array);
        if (indice == -1) {
            indice = array.size();
            array.add(valor);
        }
        return indice;
    }

    /**
     * Busca Si un valor se encuentra en la lista
     * @param valor
     * @param array
     * @return
     */
    private int BuscarValor(String valor, ArrayList<String> array) {
        for (int i = 0; i < array.size(); i++) {
            if (array.get(i).equals(valor)) {
                return i;
            }
        }
        return -1;
    }

    /**
     * Obtener el indice de un titulo de columna
     * @param titulos
     * @param nombre
     * @return
     */
    private int getIndiceTitulo(String[] titulos, String nombre) {
        for (int i = 0; i < titulos.length; i++) {
            if (titulos[i].equals(nombre)) {
                return i;
            }
        }
        return -1;
    }
    //</editor-fold>

    @Override
    public String LeerReglas() {
     Regla modelo = new Regla();
        modelo.AgregarRegla(reglas.get(0).getNombreAtributo(0), reglas.get(0).getValor(0));
        String regla = "";
        String filejava = "";
        for (int i = 0; i < reglas.size(); i++) {
            regla += (i + 1) + ".";
            filejava += "if(";
            Regla r = reglas.get(i);
            int cantidad = r.getCantidad();
            for (int j = 0; j < cantidad; j++) {
                if (j > 0) {
                    regla += " &&";
                    filejava += " && ";
                    
                }
                regla += " " + r.getNombreAtributo(j) + "=" + r.getValor(j);
                filejava += "(" + '"' + r.getValor(j) + '"' + ".equalsIgnoreCase(" + r.getNombreAtributo(j) + "))";
            }

            regla += " ==> " + r.getNombreClase() + "=" + r.getValorClase() + "\n";
            filejava += "){label.setText(" +'"'+ r.getValorClase() + '"' + ");}" + "\n";

        }
         Plantilla.setSentencias(filejava);
        return regla;
    }

    //obtiene el indice gini de una columna en relación con la clase.
    private double giniColumna(ArrayList<TablaGini> tablas, int cantidadRegistros) {
        double giniTablas = 0;
        for (int i = 0; i < tablas.size(); i++) {
            double inicial = ((double) tablas.get(i).cantidadColumna / cantidadRegistros);
            giniTablas += inicial * tablas.get(i).gini;
        }
        return giniTablas;
    }

    //elimina los registros que ya se encuentran en niveles anteriores y no se deben utilizar
    private ArrayList<ArrayList<String>> limpiarTabla(ArrayList<ArrayList<String>> datos, int posicionColumna, String valor) {

        for (int j = 0; j < datos.size(); j++) {
            if (!datos.get(j).get(posicionColumna).equals(valor)) {
                datos.remove(j);
                j--;
            }
        }

        for (int i = 0; i < datos.size(); i++) {
            for (int j = 0; j < datos.get(i).size(); j++) {
                System.out.print(datos.get(i).get(j) + " ");
            }
            System.out.println("\n");
        }
        return datos;
    }

    private boolean estaUsado(String string) {
        boolean usado = false;

        for (int i = 0; i < usados.size(); i++) {
            if (usados.get(i).equals(string)) {
                usado = true;
            }
        }

        return usado;
    }

    @Override
    public String LeerReglasProlog() {
        
        
        //Campos seleccionados en la UI y su valores en la DB incluida la clase
        String camposConClase[] = formatear(datos.getTitulos());
        //Valores de esos campos

        //Un nuevo vector que almacenará los campos sin la clase
        String campos[] = new String[camposConClase.length - 1];
        ArrayList<ArrayList<String>> valoresCampos = datos.getPosiblesValores();

        int indiceCampo = 0;

        //Quitamos la clase de los campos
        for (int l = 0; l < camposConClase.length; l++) {

            if (!camposConClase[l].equals(formatear(datos.getNombreClase()))) {
                campos[indiceCampo++] = camposConClase[l];
            } else {
                valoresCampos.remove(l);
            }


        }
        
        char variables[] = new char[campos.length];

        //Sacamos la cantidad de variables necesarias del abecedario en MAYÚSCULAS
        for (int i = 65; i < 65 + campos.length; i++) {

             variables[i - 65] = (char) i;

        }
        
        //La variable que sirve para guardar el resultado en PROLOG
        char variableFinal = (char) ((char)variables[variables.length-1]+1);
        
        
        
        String regla = "";
        
        //Declaramos las proposiciones y sus posibles valores
        for (int i = 0; i < campos.length; i++) {

            for (int j = 0; j < valoresCampos.get(i).size(); j++) {
                regla += campos[i] + "(" + formatear(valoresCampos.get(i).get(j)) + ").\n";
            }

            regla += "\n";

        }
        
        //Declaramos la proposición de la clase
        regla += formatear(datos.getNombreClase()) + "(";
        
        
        //Letras
        for (int i = 0; i < campos.length; i++) {

            regla += variables[i] + "";

            if (i != variables.length - 1) {
                regla += ", ";
            } else {
                regla += ", "+variableFinal+") :- ";
            }
        }
        
        //Declaraciones
        for (int i = 0; i < campos.length; i++) {

            regla += campos[i] + "(" + variables[i] + "), ";

        }
        
        

        for (int i = 0; i < reglas.size(); i++) {
            
            Regla r = reglas.get(i);
            
            regla += "(";
            
            int cantidad = r.getCantidad();
            for (int j = 0; j < cantidad; j++) {
                if (j > 0) {
                    regla += ", ";
                }
                regla += variables[this.indice(campos, formatear(r.getNombreAtributo(j)))] + "='" + formatear(r.getValor(j)) + "'";
            }

            regla += ")->" + variableFinal + "='" + formatear(reglas.get(i).getValorClase()) + "';";

        }
        return regla.substring(0, regla.length()-1)+".";
        
        
    }
    
    
    //REPETIDO
    private int indice(String[] campos, String campo) {

        for (int i = 0; i < campos.length; i++) {
            if (campos[i].equals(campo)) {
                return i;
            }
        }

        return -1;

    }

    @Override
    public Datos getDatos() {
        return datos;
    }
    
    private String formatear(String valor){
        return formatear(new String[]{valor})[0];
    }
    
    private String[] formatear(String[] valores){
        String[] nuevo = new String[valores.length];
        for (int i = 0; i < valores.length; i++) {
            String valor = valores[i].toLowerCase();
            valor = valor.replace('ñ', 'n');
            valor = valor.replace('á', 'a');
            valor = valor.replace('é', 'e');
            valor = valor.replace('í', 'i');
            valor = valor.replace('ó', 'o');
            nuevo[i] = valor.replace('ú', 'u');
        }
        
        return nuevo;
    }


}
